"use strict";

exports.__esModule = true;
require("core-js/modules/es.error.cause.js");
require("core-js/modules/esnext.iterator.constructor.js");
require("core-js/modules/esnext.iterator.for-each.js");
var _templateLiteralTag = require("../../helpers/templateLiteralTag");
var _object = require("../../helpers/object");
var _localHooks = _interopRequireDefault(require("../../mixins/localHooks"));
var C = _interopRequireWildcard(require("../../i18n/constants"));
var _element = require("../../helpers/dom/element");
var _a11y = require("../../helpers/a11y");
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function _classPrivateMethodInitSpec(e, a) { _checkPrivateRedeclaration(e, a), a.add(e); }
function _classPrivateFieldInitSpec(e, t, a) { _checkPrivateRedeclaration(e, t), t.set(e, a); }
function _checkPrivateRedeclaration(e, t) { if (t.has(e)) throw new TypeError("Cannot initialize the same private elements twice on an object"); }
function _classPrivateFieldGet(s, a) { return s.get(_assertClassBrand(s, a)); }
function _classPrivateFieldSet(s, a, r) { return s.set(_assertClassBrand(s, a), r), r; }
function _assertClassBrand(e, t, n) { if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n; throw new TypeError("Private element is not present on this object"); }
const TEMPLATE = `
<div data-ref="container" class="ht-pagination handsontable">
  <div class="ht-pagination__inner">
    <div data-ref="pageSizeSection" class="ht-page-size-section">
      <span data-ref="pageSizeLabel" class="ht-page-size-section__label"></span>
      <div class="ht-page-size-section__select-wrapper">
        <select data-ref="pageSizeSelect" name="pageSize" data-hot-input></select>
      </div>
    </div>
    <div data-ref="pageCounterSection" class="ht-page-counter-section"></div>
    <nav data-ref="pageNavSection" class="ht-page-navigation-section">
      <button data-ref="first" class="ht-page-navigation-section__button ht-page-first"></button>
      <button data-ref="prev" class="ht-page-navigation-section__button ht-page-prev"></button>
      <span data-ref="pageNavLabel" class="ht-page-navigation-section__label"></span>
      <button data-ref="next" class="ht-page-navigation-section__button ht-page-next"></button>
      <button data-ref="last" class="ht-page-navigation-section__button ht-page-last"></button>
    </nav>
  </div>
</div>
`;

/**
 * PaginationUI is a UI component that renders and manages pagination controls.
 * It handles user interactions (navigation and page size changes), and exposes methods to
 * toggle visibility of pagination sections and update the state of the pagination controls.
 *
 * @private
 * @class PaginationUI
 */
var _rootElement = /*#__PURE__*/new WeakMap();
var _uiContainer = /*#__PURE__*/new WeakMap();
var _isRtl = /*#__PURE__*/new WeakMap();
var _refs = /*#__PURE__*/new WeakMap();
var _themeName = /*#__PURE__*/new WeakMap();
var _phraseTranslator = /*#__PURE__*/new WeakMap();
var _shouldHaveBorder = /*#__PURE__*/new WeakMap();
var _a11yAnnouncer = /*#__PURE__*/new WeakMap();
var _PaginationUI_brand = /*#__PURE__*/new WeakSet();
class PaginationUI {
  constructor(_ref) {
    let {
      rootElement,
      uiContainer,
      isRtl,
      themeName,
      phraseTranslator,
      shouldHaveBorder,
      a11yAnnouncer
    } = _ref;
    /**
     * Updates the visibility of the pagination container based on the visibility of its sections.
     */
    _classPrivateMethodInitSpec(this, _PaginationUI_brand);
    /**
     * The root element where the pagination UI will be installed.
     *
     * @type {HTMLElement}
     */
    _classPrivateFieldInitSpec(this, _rootElement, void 0);
    /**
     * The container element where the pagination UI will be installed.
     * If not provided, the pagination container will be injected after the root element.
     *
     * @type {HTMLElement}
     */
    _classPrivateFieldInitSpec(this, _uiContainer, void 0);
    /**
     * Indicates if the UI is in RTL mode.
     *
     * @type {boolean}
     */
    _classPrivateFieldInitSpec(this, _isRtl, false);
    /**
     * The references to the UI elements.
     *
     * @type {object}
     */
    _classPrivateFieldInitSpec(this, _refs, void 0);
    /**
     * The name of the current theme.
     *
     * @type {string | undefined}
     */
    _classPrivateFieldInitSpec(this, _themeName, void 0);
    /**
     * A function to translate phrases used in the UI.
     *
     * @type {function(string): string}
     */
    _classPrivateFieldInitSpec(this, _phraseTranslator, void 0);
    /**
     * A function that determines whether the pagination should have a border.
     *
     * @type {function(): void}
     */
    _classPrivateFieldInitSpec(this, _shouldHaveBorder, void 0);
    /**
     * A function allowing to announce accessibility messages.
     *
     * @type {function(string): void}
     */
    _classPrivateFieldInitSpec(this, _a11yAnnouncer, void 0);
    _classPrivateFieldSet(_rootElement, this, rootElement);
    _classPrivateFieldSet(_uiContainer, this, uiContainer);
    _classPrivateFieldSet(_isRtl, this, isRtl);
    _classPrivateFieldSet(_themeName, this, themeName);
    _classPrivateFieldSet(_phraseTranslator, this, phraseTranslator);
    _classPrivateFieldSet(_shouldHaveBorder, this, shouldHaveBorder);
    _classPrivateFieldSet(_a11yAnnouncer, this, a11yAnnouncer);
    this.install();
  }

  /**
   * Creates the pagination UI elements and sets up event listeners.
   */
  install() {
    var _classPrivateFieldGet2;
    if ((_classPrivateFieldGet2 = _classPrivateFieldGet(_refs, this)) !== null && _classPrivateFieldGet2 !== void 0 && _classPrivateFieldGet2.container) {
      return;
    }
    const elements = (0, _templateLiteralTag.html)`${TEMPLATE}`;
    const {
      container,
      first,
      prev,
      next,
      last,
      pageSizeSelect
    } = elements.refs;
    _classPrivateFieldSet(_refs, this, elements.refs);
    container.setAttribute('dir', _classPrivateFieldGet(_isRtl, this) ? 'rtl' : 'ltr');
    const isDisabled = event => event.currentTarget.disabled;
    const addClickListener = (eventName, element, callback) => {
      element.addEventListener(eventName, event => {
        if (!isDisabled(event)) {
          callback();
        }
      });
    };
    addClickListener('click', first, () => this.runLocalHooks('firstPageClick'));
    addClickListener('focus', first, () => this.runLocalHooks('focus', first));
    addClickListener('click', prev, () => this.runLocalHooks('prevPageClick'));
    addClickListener('focus', prev, () => this.runLocalHooks('focus', prev));
    addClickListener('click', next, () => this.runLocalHooks('nextPageClick'));
    addClickListener('focus', next, () => this.runLocalHooks('focus', next));
    addClickListener('click', last, () => this.runLocalHooks('lastPageClick'));
    addClickListener('focus', last, () => this.runLocalHooks('focus', last));
    addClickListener('focus', pageSizeSelect, () => this.runLocalHooks('focus', pageSizeSelect));
    pageSizeSelect.addEventListener('change', () => {
      const value = pageSizeSelect.value === 'auto' ? 'auto' : Number.parseInt(pageSizeSelect.value, 10);
      this.runLocalHooks('pageSizeChange', value);
    });
    this.setCounterSectionVisibility(false);
    this.setNavigationSectionVisibility(false);
    this.setPageSizeSectionVisibility(false);
    if (_classPrivateFieldGet(_uiContainer, this)) {
      _classPrivateFieldGet(_uiContainer, this).appendChild(elements.fragment);
      (0, _element.addClass)(container, [_classPrivateFieldGet(_themeName, this), 'handsontable']);
    } else {
      _classPrivateFieldGet(_rootElement, this).after(elements.fragment);
    }
  }

  /**
   * Gets the pagination element.
   *
   * @returns {HTMLElement} The pagination element.
   */
  getContainer() {
    return _classPrivateFieldGet(_refs, this).container;
  }

  /**
   * Gets the focusable elements.
   *
   * @returns {HTMLElement[]} The focusable elements.
   */
  getFocusableElements() {
    const {
      first,
      prev,
      next,
      last,
      pageSizeSelect
    } = _classPrivateFieldGet(_refs, this);
    return [pageSizeSelect, first, prev, next, last].filter(element => !element.disabled);
  }

  /**
   * Updates the width of the pagination container.
   *
   * @param {number} width The new width of the pagination container.
   * @returns {PaginationUI} The instance of the PaginationUI for method chaining.
   */
  updateWidth(width) {
    _classPrivateFieldGet(_refs, this).container.style.width = `${width}px`;
    return this;
  }

  /**
   * Updates the theme of the pagination container.
   *
   * @param {string | false | undefined} themeName The name of the theme to use.
   * @returns {PaginationUI} The instance of the PaginationUI for method chaining.
   */
  updateTheme(themeName) {
    _classPrivateFieldSet(_themeName, this, themeName);
    if (_classPrivateFieldGet(_uiContainer, this)) {
      const {
        container
      } = _classPrivateFieldGet(_refs, this);
      (0, _element.removeClass)(container, /ht-theme-.*/g);
      if (_classPrivateFieldGet(_themeName, this)) {
        (0, _element.addClass)(container, _classPrivateFieldGet(_themeName, this));
      }
    }
    return this;
  }

  /**
   * Gets the height of the pagination container element.
   *
   * @returns {number}
   */
  getHeight() {
    return _classPrivateFieldGet(_refs, this).container.offsetHeight;
  }

  /**
   * Refreshes the border state of the pagination container based on the external condition.
   *
   * @returns {PaginationUI} The instance of the PaginationUI for method chaining.
   */
  refreshBorderState() {
    const {
      container
    } = _classPrivateFieldGet(_refs, this);
    if (_classPrivateFieldGet(_uiContainer, this) || _classPrivateFieldGet(_shouldHaveBorder, this).call(this)) {
      (0, _element.addClass)(container, 'ht-pagination--bordered');
    } else {
      (0, _element.removeClass)(container, 'ht-pagination--bordered');
    }
    return this;
  }

  /**
   * Updates the state of the pagination UI.
   *
   * @param {object} state The pagination state.
   * @param {number} state.currentPage The current page number.
   * @param {number} state.totalPages The total number of pages.
   * @param {number} state.firstVisibleRowIndex The index of the first visible row on the current page.
   * @param {number} state.lastVisibleRowIndex The index of the last visible row on the current page.
   * @param {number} state.totalRenderedRows The total number of renderable rows.
   * @param {Array<number | 'auto'>} state.pageSizeList The list of available page sizes.
   * @param {number} state.pageSize The current page size.
   * @param {boolean} state.autoPageSize Indicates if the page size is set to 'auto'.
   * @returns {PaginationUI} The instance of the PaginationUI for method chaining.
   */
  updateState(_ref2) {
    let {
      currentPage,
      totalPages,
      firstVisibleRowIndex,
      lastVisibleRowIndex,
      totalRenderedRows,
      pageSizeList,
      pageSize,
      autoPageSize
    } = _ref2;
    const {
      first,
      prev,
      next,
      last,
      pageCounterSection,
      pageNavSection,
      pageNavLabel,
      pageSizeSelect,
      pageSizeLabel
    } = _classPrivateFieldGet(_refs, this);
    const counterSectionText = _classPrivateFieldGet(_phraseTranslator, this).call(this, C.PAGINATION_COUNTER_SECTION, {
      start: firstVisibleRowIndex + 1,
      end: lastVisibleRowIndex + 1,
      total: totalRenderedRows
    });
    const navLabelText = _classPrivateFieldGet(_phraseTranslator, this).call(this, C.PAGINATION_NAV_SECTION, {
      currentPage,
      totalPages
    });
    const pageSizeLabelText = _classPrivateFieldGet(_phraseTranslator, this).call(this, C.PAGINATION_PAGE_SIZE_SECTION);
    pageCounterSection.textContent = counterSectionText;
    pageNavLabel.textContent = navLabelText;
    pageSizeSelect.textContent = '';
    pageSizeLabel.textContent = `${pageSizeLabelText}:`;
    (0, _element.setAttribute)(pageNavSection, [...[(0, _a11y.A11Y_LABEL)(_classPrivateFieldGet(_phraseTranslator, this).call(this, C.PAGINATION_SECTION))]]);
    (0, _element.setAttribute)(pageSizeSelect, [...[(0, _a11y.A11Y_LABEL)(_classPrivateFieldGet(_phraseTranslator, this).call(this, C.PAGINATION_PAGE_SIZE_SECTION))], ...[(0, _a11y.A11Y_TABINDEX)(-1)]]);
    _classPrivateFieldGet(_a11yAnnouncer, this).call(this, navLabelText);
    this.refreshBorderState();
    pageSizeList.forEach(pageSizeItem => {
      const label = pageSizeItem === 'auto' ? _classPrivateFieldGet(_phraseTranslator, this).call(this, C.PAGINATION_PAGE_SIZE_AUTO) : pageSizeItem;
      const option = new Option(label, pageSizeItem);
      if (autoPageSize && pageSizeItem === 'auto' || !autoPageSize && pageSizeItem === pageSize) {
        option.selected = true;
      }
      pageSizeSelect.add(option);
    });
    const isFirstPage = currentPage === 1;
    const isLastPage = currentPage === totalPages;
    if (pageNavSection.style.display !== 'none') {
      const activeElement = _classPrivateFieldGet(_rootElement, this).ownerDocument.activeElement;
      if (isFirstPage) {
        (0, _element.addClass)(first, 'ht-page-navigation-section__button--disabled');
        (0, _element.addClass)(prev, 'ht-page-navigation-section__button--disabled');
        first.disabled = true;
        prev.disabled = true;
      } else {
        (0, _element.removeClass)(first, 'ht-page-navigation-section__button--disabled');
        (0, _element.removeClass)(prev, 'ht-page-navigation-section__button--disabled');
        first.disabled = false;
        prev.disabled = false;
      }
      if (isLastPage) {
        (0, _element.addClass)(next, 'ht-page-navigation-section__button--disabled');
        (0, _element.addClass)(last, 'ht-page-navigation-section__button--disabled');
        next.disabled = true;
        last.disabled = true;
      } else {
        (0, _element.removeClass)(next, 'ht-page-navigation-section__button--disabled');
        (0, _element.removeClass)(last, 'ht-page-navigation-section__button--disabled');
        next.disabled = false;
        last.disabled = false;
      }
      if ([first, prev, next, last].includes(activeElement)) {
        if (prev.disabled) {
          next.focus();
        } else if (next.disabled) {
          prev.focus();
        }
      }
    }
    (0, _element.setAttribute)(first, [...[(0, _a11y.A11Y_LABEL)(_classPrivateFieldGet(_phraseTranslator, this).call(this, C.PAGINATION_FIRST_PAGE))], ...[(0, _a11y.A11Y_DISABLED)(isFirstPage)], ...[(0, _a11y.A11Y_TABINDEX)(-1)]]);
    (0, _element.setAttribute)(prev, [...[(0, _a11y.A11Y_LABEL)(_classPrivateFieldGet(_phraseTranslator, this).call(this, C.PAGINATION_PREV_PAGE))], ...[(0, _a11y.A11Y_DISABLED)(isFirstPage)], ...[(0, _a11y.A11Y_TABINDEX)(-1)]]);
    (0, _element.setAttribute)(next, [...[(0, _a11y.A11Y_LABEL)(_classPrivateFieldGet(_phraseTranslator, this).call(this, C.PAGINATION_NEXT_PAGE))], ...[(0, _a11y.A11Y_DISABLED)(isLastPage)], ...[(0, _a11y.A11Y_TABINDEX)(-1)]]);
    (0, _element.setAttribute)(last, [...[(0, _a11y.A11Y_LABEL)(_classPrivateFieldGet(_phraseTranslator, this).call(this, C.PAGINATION_LAST_PAGE))], ...[(0, _a11y.A11Y_DISABLED)(isLastPage)], ...[(0, _a11y.A11Y_TABINDEX)(-1)]]);
    return this;
  }

  /**
   * Sets the visibility of the page size section.
   *
   * @param {boolean} isVisible True to show the page size section, false to hide it.
   * @returns {PaginationUI} The instance of the PaginationUI for method chaining.
   */
  setPageSizeSectionVisibility(isVisible) {
    const {
      pageSizeSection,
      pageSizeSelect
    } = _classPrivateFieldGet(_refs, this);
    pageSizeSection.style.display = isVisible ? '' : 'none';
    pageSizeSelect.disabled = !isVisible;
    _assertClassBrand(_PaginationUI_brand, this, _updateContainerVisibility).call(this);
    return this;
  }

  /**
   * Sets the visibility of the page counter section.
   *
   * @param {boolean} isVisible True to show the page size section, false to hide it.
   * @returns {PaginationUI} The instance of the PaginationUI for method chaining.
   */
  setCounterSectionVisibility(isVisible) {
    _classPrivateFieldGet(_refs, this).pageCounterSection.style.display = isVisible ? '' : 'none';
    _assertClassBrand(_PaginationUI_brand, this, _updateContainerVisibility).call(this);
    return this;
  }

  /**
   * Sets the visibility of the page navigation section.
   *
   * @param {boolean} isVisible True to show the page size section, false to hide it.
   * @returns {PaginationUI} The instance of the PaginationUI for method chaining.
   */
  setNavigationSectionVisibility(isVisible) {
    const {
      pageNavSection,
      first,
      prev,
      next,
      last
    } = _classPrivateFieldGet(_refs, this);
    pageNavSection.style.display = isVisible ? '' : 'none';
    first.disabled = !isVisible;
    prev.disabled = !isVisible;
    next.disabled = !isVisible;
    last.disabled = !isVisible;
    _assertClassBrand(_PaginationUI_brand, this, _updateContainerVisibility).call(this);
    return this;
  }
  /**
   * Removes the pagination UI elements from the DOM and clears the refs.
   */
  destroy() {
    var _classPrivateFieldGet3;
    (_classPrivateFieldGet3 = _classPrivateFieldGet(_refs, this)) === null || _classPrivateFieldGet3 === void 0 || _classPrivateFieldGet3.container.remove();
    _classPrivateFieldSet(_refs, this, null);
  }
}
exports.PaginationUI = PaginationUI;
function _updateContainerVisibility() {
  const {
    container,
    pageSizeSection,
    pageCounterSection,
    pageNavSection
  } = _classPrivateFieldGet(_refs, this);
  const isSectionVisible = pageSizeSection.style.display !== 'none' || pageCounterSection.style.display !== 'none' || pageNavSection.style.display !== 'none';

  // adds or removes the corner around the Handsontable root element
  if (!_classPrivateFieldGet(_uiContainer, this)) {
    if (isSectionVisible) {
      (0, _element.addClass)(_classPrivateFieldGet(_rootElement, this).querySelector('.ht-wrapper'), 'htPagination');
    } else {
      (0, _element.removeClass)(_classPrivateFieldGet(_rootElement, this).querySelector('.ht-wrapper'), 'htPagination');
    }
  }
  container.style.display = isSectionVisible ? '' : 'none';
}
(0, _object.mixin)(PaginationUI, _localHooks.default);